#include <dspSimulator/instruction/spmask.h>

bool SPMASK::checkCondition(std::shared_ptr<DspMachine> dspMachine) {
    return true;
}

void SPMASK::loadInstIRIntoJit(llvm::LLVMContext *llvmContext, llvm::Module *module,
                               std::shared_ptr<llvm::IRBuilder<>> irBuilder) {

}

std::shared_ptr<Instruction> SPMASK::decode(std::shared_ptr<InstInfo> instInfo, u64 baseCycle) {
    std::shared_ptr<SPMASK> spmask;
    auto dspInstInfo = std::dynamic_pointer_cast<DspInstInfo>(instInfo);
    bool isStandardInst = dspInstInfo->isStandardInstruction();
    if (isStandardInst) {
        auto data = vectorToBitSet<32>(dspInstInfo->getBits());
        if (checkBits<6>(data, 26, 0b000000) && checkBits<16>(data, 2, 0b1101000000000000) &&
            extractBits<8>(data, 18).to_ulong() != 0) {
            spmask = std::make_shared<SPMASK>(dspInstInfo->getAddress(), baseCycle);
            spmask->spMaskBitset = extractBits<8>(data, 18);
            spmask->s = data[1];
            spmask->p = data[0];
        } else if (checkBits<6>(data, 26, 0b000000) && checkBits<16>(data, 2, 0b1100000000000000)) {
            spmask = std::make_shared<SPMASK>(dspInstInfo->getAddress(), baseCycle);
            spmask->spMaskBitset = extractBits<8>(data, 18);
            spmask->s = data[1];
            spmask->p = data[0];
        }
    } else {
        auto data = vectorToBitSet<16>(dspInstInfo->getBits());
        if (checkBits<4>(data, 10, 0b1011) && checkBits<6>(data, 1, 0b110011)) {
            spmask = std::make_shared<SPMASK>(dspInstInfo->getAddress(), baseCycle);
            spmask->isCompactInstruction = true;
            spmask->compactInstKind = "Uspm";
            spmask->spMaskBitset[0] = data[0];
            spmask->spMaskBitset[1] = data[7];
            spmask->spMaskBitset[2] = data[8];
            spmask->spMaskBitset[3] = data[9];
            spmask->spMaskBitset[4] = data[14];
            spmask->spMaskBitset[5] = data[15];
            spmask->DSZ = dspInstInfo->getDSZ();
            spmask->RS = dspInstInfo->getRS();
            spmask->SAT = dspInstInfo->getSAT();
            spmask->PROT = dspInstInfo->getPROT();
            spmask->BR = dspInstInfo->getBR();
            spmask->p = dspInstInfo->getP();
        }
    }
    return spmask;
}

void SPMASK::executeCustom(std::shared_ptr<TargetMachine> targetMachine, ExecutePhase executePhase) {

}

std::shared_ptr<DspInstruction> SPMASK::clone() {
    return std::make_shared<SPMASK>(*this);
}

std::string SPMASK::toString() const {
    std::string res = m_name + " ";
    if (spMaskBitset[0])
        res += "L1 ";
    if (spMaskBitset[1]) {
        res += "L2 ";
    }
    if (spMaskBitset[2]) {
        res += "S1 ";
    }
    if (spMaskBitset[3]) {
        res += "S2 ";
    }
    if (spMaskBitset[4]) {
        res += "D1 ";
    }
    if (spMaskBitset[5]) {
        res += "D2 ";
    }
    if (spMaskBitset[6]) {
        res += "M1 ";
    }
    if (spMaskBitset[7]) {
        res += "M2 ";
    }
    return res;
}
